package cn.com.lyb.aspect;

import cn.com.lyb.annotation.Retryable;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 重试机制
 */

@Aspect
@Component
public class RetryAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(RetryAspect.class);

    @Around("@annotation(retryable)")
    public Object retry(ProceedingJoinPoint joinPoint, Retryable retryable) throws Throwable {
        int maxAttempts = retryable.maxAttempts();
        Class<? extends Throwable>[] retryOn = retryable.retryOn();
        int attempts = 0;
        do {
            attempts++;
            try {
                return joinPoint.proceed();
            } catch (Throwable e) {
                boolean retry = false;
                for (Class<? extends Throwable> exception : retryOn) {
                    if (exception.isInstance(e)) {
                        retry = true;
                        break;
                    }
                }
                if (!retry || attempts >= maxAttempts) {
                    throw e;
                }
                LOGGER.warn("Retry attempt {} for method {}", attempts, joinPoint.getSignature().toShortString());
            }
        } while (attempts < maxAttempts);
        throw new IllegalStateException("Unreachable");
    }
}
